﻿#pragma once

#include "boost/json.hpp"
namespace json = boost::json;

#include <memory>
#include <msgpack.hpp>

// 请求中方法名或参数不足
class error_args_count : public std::invalid_argument {
public:
    using _Mybase = std::invalid_argument;
    explicit error_args_count(const char* _Message = "Arguments not enough!")
        : _Mybase(_Message) {}
};

// 请求中参数类型错误
class error_args_type : public std::invalid_argument {
public:
    using _Mybase = std::invalid_argument;
    explicit error_args_type(const char* _Message = "Arguments type error!")
        : _Mybase(_Message) {}
};

namespace msgpack {
/**
 * @brief 基于 msgpack 的序列化类；有状态的，需要按顺序流入/流出
 */
class serializer {
public:
    typedef std::shared_ptr<serializer> ptr;

    serializer()
        : m_pker(&m_sbuf) {}

    serializer(const char* data, size_t size)
        : serializer() {
        m_unpker.reserve_buffer(size);
        memcpy(m_unpker.buffer(), data, size);
        m_unpker.buffer_consumed(size);
    }

    serializer(char* data, size_t size)
        : serializer() {
        m_unpker.reserve_buffer(size);
        memcpy(m_unpker.buffer(), data, size);
        m_unpker.buffer_consumed(size);
    }

    void reset() { m_sbuf.clear(); }
    void clear() { reset(); }

    template<typename Tuple, std::size_t Id>
    void getv(serializer& ds, Tuple& t) {
        ds >> std::get<Id>(t);
    }

    template<typename Tuple, std::size_t... I>
    Tuple get_tuple(std::index_sequence<I...>) {
        Tuple t;
        std::initializer_list<int>{(getv<Tuple, I>(*this, t), 0)...};
        return t;
    }

    template<typename T>
    serializer& operator<<(T i) {
        m_pker.pack(i);
        return *this;
    }

    template<>
    serializer& operator<<(json::value i) {
        m_pker.pack(json::serialize(i));
        return *this;
    }

    template<>
    serializer& operator<<(const json::value& i) {
        m_pker.pack(json::serialize(i));
        return *this;
    }

    template<typename T>
    serializer& operator>>(T& i) {
        msgpack::object_handle oh;

        // get next
        if (!m_unpker.next(oh)) {
            // 参数数量不足
            throw error_args_count();
        }

        // 检查参数类型
        try {
            oh.get().convert(i);
        } catch (msgpack::type_error& /*er*/) {
            throw error_args_type();
        }

        return *this;
    }

    template<>
    serializer& operator>>(json::value& i) {
        msgpack::object_handle oh;

        // get next
        if (!m_unpker.next(oh)) {
            // 参数数量不足
            throw error_args_count();
        }

        std::string m;

        // 检查参数类型
        try {
            oh.get().convert(m);
            i = json::parse(m);
        } catch (msgpack::type_error& /*er*/) {
            throw error_args_type();
        }

        return *this;
    }

    const char* data() { return m_sbuf.data(); }
    size_t      size() { return m_sbuf.size(); }

private:
    // 缓存
    msgpack::sbuffer m_sbuf;
    // 打包器
    msgpack::packer<msgpack::sbuffer> m_pker;
    // 解包器
    msgpack::unpacker m_unpker;
};

}   // namespace msgpack

typedef msgpack::serializer msgpack_serializer;